// $Id: RepositoryService.java 85 2012-02-25 15:01:58Z huijzer@gmail.com $
package lime.service;

import static lime.common.DQLQuery.SELECT_ALL_CABINETS;
import static lime.common.DQLQuery.SELECT_ALL_GROUPS;
import static lime.common.DQLQuery.SELECT_ALL_USERS;
import static lime.common.DQLQuery.SELECT_GROUP_CLASSES;

import java.util.ArrayList;
import java.util.List;

import lime.common.DQLQuery;
import lime.common.DQLTemplate;
import lime.common.LimeException;
import lime.model.Cabinet;
import lime.model.Document;
import lime.model.Folder;
import lime.model.Group;
import lime.model.Rendition;
import lime.model.User;
import lime.model.Version;

import org.apache.commons.lang.StringUtils;

import com.documentum.com.DfClientX;
import com.documentum.com.IDfClientX;
import com.documentum.fc.client.IDfClient;
import com.documentum.fc.client.IDfCollection;
import com.documentum.fc.client.IDfDocbaseMap;
import com.documentum.fc.client.IDfSession;
import com.documentum.fc.client.IDfSessionManager;
import com.documentum.fc.client.IDfSysObject;
import com.documentum.fc.client.IDfTypedObject;
import com.documentum.fc.common.DfException;
import com.documentum.fc.common.DfId;
import com.documentum.fc.common.IDfLoginInfo;
import com.documentum.fc.common.IDfValue;

public class RepositoryService {

	private IDfSessionManager sessionManager;
	private IDfSession session;
	private DQLTemplate dqlTemplate;

	public void connect(String repository, String username, String password) {
		try {

			IDfClientX cx = new DfClientX();
			IDfClient client = cx.getLocalClient();

			IDfLoginInfo loginInfo = cx.getLoginInfo();
			loginInfo.setUser(username);
			loginInfo.setPassword(password);
			loginInfo.setDomain("");

			sessionManager = client.newSessionManager();
			sessionManager.setIdentity(repository, loginInfo);
			session = sessionManager.getSession(repository);

			dqlTemplate = new DQLTemplate(session);

		} catch (DfException e) {
			throw new LimeException(e);
		}
	}

	public void disconnect() {
		if (sessionManager != null && session != null) {
			sessionManager.release(session);
		}
	}

	public DQLTemplate getDqlTemplate() {
		return dqlTemplate;
	}

	public IDfSession getSession() {
		return session;
	}

	public boolean isConnected() {
		if (session != null) {
			return session.isConnected();
		} else {
			return false;
		}
	}

	/**
	 * Get a list of available repositories.
	 * 
	 * @return List of repositories
	 */
	public List<String> getRepositories() {
		List<String> repositories = new ArrayList<String>();

		try {

			IDfClientX cx = new DfClientX();
			IDfClient client = cx.getLocalClient();
			IDfDocbaseMap docbaseMap = client.getDocbaseMap();

			int docbaseCount = docbaseMap.getDocbaseCount();
			for (int i = 0; i < docbaseCount; i++) {
				repositories.add(docbaseMap.getDocbaseName(i));
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return repositories;
	}

	public void checkState() {
		if (!isConnected()) {
			throw new IllegalArgumentException(
					"Method should only be called when repository service is connected to a repository.");
		}
	}

	public String getConnectionInfo() {
		StringBuilder connectionInfo = new StringBuilder();

		try {
			connectionInfo.append("User: ");
			connectionInfo.append(session.getLoginUserName());
			connectionInfo.append(" | Repository: ");
			connectionInfo.append(session.getDocbaseName());
			connectionInfo.append(" | Server: ");
			connectionInfo.append(session.getServerVersion());
		} catch (DfException e) {
			throw new LimeException(e);
		}

		return connectionInfo.toString();
	}

	public List<Cabinet> getCabinets() {
		List<Cabinet> cabinetList = new ArrayList<Cabinet>();

		try {

			DQLTemplate template = new DQLTemplate(session);
			String dql = DQLQuery.get(SELECT_ALL_CABINETS);
			List<IDfTypedObject> typedObjectList = template.queryForObjects(dql);

			for (IDfTypedObject typedObject : typedObjectList) {
				String id = typedObject.getString("r_object_id");
				String name = typedObject.getString("object_name");
				Cabinet cabinet = new Cabinet(id, name);
				cabinet.setPrivate(typedObject.getBoolean("is_private"));
				cabinetList.add(cabinet);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return cabinetList;
	}

	public List<Folder> getFolders(String folderId) {
		List<Folder> folderList = new ArrayList<Folder>();

		try {

			DQLTemplate template = new DQLTemplate(session);
			String dql = String.format(
					"select r_object_id, object_name from dm_folder where any i_folder_id = '%s' order by object_name",
					folderId);
			List<IDfTypedObject> typedObjectList = template.queryForObjects(dql);
			for (IDfTypedObject typedObject : typedObjectList) {
				String id = typedObject.getString("r_object_id");
				String name = typedObject.getString("object_name");
				Folder folder = new Folder(id, name);
				folderList.add(folder);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return folderList;
	}

	public List<Document> getDocuments(String folderId) {
		List<Document> documentList = new ArrayList<Document>();

		try {

			DQLTemplate template = new DQLTemplate(session);
			String dql = String
					.format("select r_object_id, object_name, r_lock_owner from dm_sysobject where any i_folder_id = '%s' and r_object_id not in (select r_object_id from dm_folder where any i_folder_id = '%s') order by object_name",
							folderId, folderId);
			List<IDfTypedObject> typedObjectList = template.queryForObjects(dql);
			for (IDfTypedObject typedObject : typedObjectList) {
				String id = typedObject.getString("r_object_id");
				String name = typedObject.getString("object_name");
				String lockOwner = typedObject.getString("r_lock_owner");
				Document document = new Document(id, name);
				document.setCheckedOut(StringUtils.isNotEmpty(lockOwner));
				documentList.add(document);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return documentList;
	}

	public List<Rendition> getRenditions(String objectId) {
		List<Rendition> renditionList = new ArrayList<Rendition>();

		IDfCollection collection = null;
		try {
			IDfSysObject sysObject = (IDfSysObject) session.getObject(new DfId(objectId));
			collection = sysObject.getRenditions("r_object_id, full_format, content_size, set_time, set_file");
			while (collection.next()) {
				Rendition rendition = new Rendition(collection.getString("r_object_id"),
						collection.getString("full_format"));
				rendition.setFullFormat(collection.getString("full_format"));
				rendition.setContentSize(collection.getString("content_size"));
				rendition.setSetTime(collection.getString("set_time"));
				rendition.setSetFile(collection.getString("set_file"));
				renditionList.add(rendition);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		} finally {
			if (collection != null) {
				try {
					collection.close();
				} catch (DfException e) {
					throw new LimeException(e);
				}
			}
		}

		return renditionList;
	}

	public List<Version> getVersions(String objectId) {
		List<Version> versionList = new ArrayList<Version>();

		IDfCollection collection = null;
		try {
			IDfSysObject sysObject = (IDfSysObject) session.getObject(new DfId(objectId));
			collection = sysObject.getVersions(null);
			while (collection.next()) {
				Version version = new Version(collection.getString("r_object_id"), collection.getString("object_name"));

				version.setVersionLabel(collection.getAllRepeatingStrings("r_version_label", ","));
				version.setModifyDate(collection.getString("r_modify_date"));
				version.setModifier(collection.getString("r_modifier"));
				version.setLogEntry(collection.getString("log_entry"));
				version.setObjectType(collection.getString("r_object_type"));
				version.setContentType(collection.getString("a_content_type"));
				version.setLockOwner(collection.getString("r_lock_owner"));
				version.setLinkCnt(collection.getString("r_link_cnt"));
				version.setIsReplica(collection.getString("i_is_replica"));

				versionList.add(version);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		} finally {
			if (collection != null) {
				try {
					collection.close();
				} catch (DfException e) {
					throw new LimeException(e);
				}
			}
		}

		return versionList;
	}

	public List<String> getGroupClasses() {
		List<String> groupClasses = new ArrayList<String>();

		try {

			DQLTemplate template = new DQLTemplate(session);
			String dql = DQLQuery.get(SELECT_GROUP_CLASSES);

			List<IDfValue> values = template.queryForValues(dql);
			for (IDfValue value : values) {
				groupClasses.add(value.asString());
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return groupClasses;
	}

	public List<Group> getGroups() {
		List<Group> groups = new ArrayList<Group>();

		try {

			DQLTemplate template = new DQLTemplate(session);
			String dql = DQLQuery.get(SELECT_ALL_GROUPS);

			List<IDfTypedObject> objects = template.queryForObjects(dql);
			for (IDfTypedObject object : objects) {
				Group group = new Group(object.getString("r_object_id"), object.getString("group_name"));
				group.setGroupClass(object.getString("group_class"));
				groups.add(group);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return groups;
	}

	public List<User> getUsers() {
		List<User> users = new ArrayList<User>();

		try {

			DQLTemplate template = new DQLTemplate(session);
			String dql = DQLQuery.get(SELECT_ALL_USERS);

			List<IDfTypedObject> objects = template.queryForObjects(dql);
			for (IDfTypedObject object : objects) {
				User user = new User(object.getString("r_object_id"), object.getString("user_name"));
				users.add(user);
			}

		} catch (DfException e) {
			throw new LimeException(e);
		}

		return users;
	}

}
